package com.roundarch.www.ui;

import java.lang.reflect.ParameterizedType;
import java.util.List;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.propertyeditors.StringTrimmerEditor;
import org.springframework.ui.Model;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;

import com.roundarch.www.DataEntity;
import com.roundarch.www.model.Files;
import com.roundarch.www.model.User;
import com.roundarch.www.service.EntityService;
import com.roundarch.www.util.StringUtils;

public abstract class AbstractEntityController<T extends DataEntity> {

	private Class<T> entityClass;
    private String rootRequestMapping;
    private EntityService entityService;
    public static final int ALL_RESULTS = 0;

    
    @SuppressWarnings("unchecked")
    public AbstractEntityController()
    {
        entityClass = (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
        RequestMapping mapping = this.getClass().getAnnotation(RequestMapping.class);
        rootRequestMapping = mapping.value()[0];
    }
	
	public String getRootRequestMapping() {
		return rootRequestMapping;
	}

	public EntityService getEntityService() {
		return entityService;
	}

	public void setEntityService(EntityService entityService) {
		this.entityService = entityService;
	}
	
	protected String buildRootUrl(String sub)
    {
        return StringUtils.joinPath(rootRequestMapping, sub);
    }

    protected String buildSaveTargetUrl(String saveTarget, T entity)
    {
        return new StringBuilder(buildRootUrl(saveTarget)).append("?id=").append(entity.getId()).toString();
    }
    
    protected String buildDeleteTargetUrl(String deleteTarget)
    {
        return new StringBuilder(buildRootUrl(deleteTarget)).toString();
    }
    
	@RequestMapping("/show")
    public String show(@ModelAttribute("entity") T entity, Model model,HttpServletRequest request)
    {
        if (entity == null || entity.isNew())
        {
            //TODO: set 'flash' acknowledging error and forward back to default (i.e. list view) 
            return "redirect:" + buildRootUrl("");
        }

        buildShowModel(entity, model,request);

        return null;
    }

	protected void buildShowModel(T entity, Model model,HttpServletRequest request)
    {
        // To be implemented by sub-classes.
    }
	
    @ModelAttribute("entity")
    public T entity(HttpServletRequest request)
    {
        String id = request.getParameter("id");
        if (StringUtils.isNotBlank(id))
            return getEntityService().find(Long.parseLong(id),getEntityClass());

        T t = BeanUtils.instantiateClass(getEntityClass());
        return t;
    }
    
    protected Class<T> getEntityClass()
    {
        return entityClass;
    }
    
    protected void buildEditModel(T entity, Model model,HttpServletRequest request)
    {
        // To be implemented by sub-classes.
    }
    @InitBinder
    public void initBinder(WebDataBinder binder)
    {
        binder.registerCustomEditor(String.class, new StringTrimmerEditor(true));
    }

    @RequestMapping("/delete")
	public String delete(@RequestParam("id") String id, HttpServletResponse response, @RequestParam(value = "deleteTarget", defaultValue = "list") String deleteTarget){
		if(id != null){
			getEntityService().delete(Long.parseLong(id), getEntityClass());
		}
		return "redirect:"+buildDeleteTargetUrl(deleteTarget);
	}
    
    @RequestMapping("/list")
	public String list(Model model, HttpServletRequest request) {
		List<T> list = getEntityService().listAll(getEntityClass());
		model.addAttribute("entities", list);
		return null;
	}

    @RequestMapping("/edit")
    public Object edit(@ModelAttribute("entity") T entity, Model model,HttpServletRequest request)
    {
        buildEditModel(null, model,request);
        return null;
    }
}
